#ifndef _SUPER_BLOCK_DATA_H
#define _SUPER_BLOCK_DATA_H

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestAssert.h>
#include <string>
#include "DiskAbstraction.h"
#include "Exception.h"
#include <iostream>

using std::cout;
using std::endl;
using std::string;

class DiskAbstraction;

class SuperBlockData
{
public:
	SuperBlockData(DiskAbstraction* da, unsigned int iNodesCount);
	~SuperBlockData(void);
	enum DataIndex {
		DISK_SIZE = 0, 
		BLOCK_SIZE = 1, 
		ROOT_INODE = 2, 
		FREE_BLOCKS_COUNT = 3,
		FIRST_FREE_BLOCKS_BLOCK = 4,
		FIRST_FREE_BLOCK_OFFSET = 5,
		LAST_FREE_BLOCKS_BLOCK = 6,
		LAST_FREE_BLOCK_OFFSET = 7,
		INODE_ARRAY_SIZE = 8,
		FREE_INODES_COUNT = 9,
		FIRST_FREE_INODES_BLOCK = 10,
		FIRST_FREE_INODE_OFFSET = 11,
		LAST_FREE_INODS_BLOCK = 12,
		LAST_FREE_INODE_OFFSET = 13};
		unsigned int get(DataIndex type);
		void set(DataIndex type, unsigned int value);
		unsigned int getExtraFreeInodesBlocksCount();
		unsigned int getExtraFreeBlocksBlocksCount();
private:
	void initSuperBlock(unsigned int iNodesCount);
	void buildFreeInodesBlock(unsigned int iNodesCount,unsigned int* metaDataContainer);
	void buildFreeBlocksBlock(unsigned int iNodesCount,unsigned int* metaDataContainer);
	void writeMetaDataAddresses(unsigned int target, unsigned int startAddress, unsigned int endAddress,unsigned int nextBlock);
	void calculateTotalExtraBlocks(unsigned int iNodesCount);
private:
	DiskAbstraction* _da;
	unsigned int _extraFreeInodesBlocks;
	unsigned int _extraFreeBlocksBlocks;
	unsigned int _diskSize;
	unsigned int _blockSize;
	unsigned int _inodeArraySize;
	//Block0 - General Data Block(GeneralData, Block Control Data, iNode Control)

	//Block1 - Block of free Blocks
	//Block2 - Block of free iNodes

};

class SuperBlockDataTestCase : public CPPUNIT_NS::TestCase {
	CPPUNIT_TEST_SUITE(SuperBlockDataTestCase);
	CPPUNIT_TEST_EXCEPTION(testNullDA, Exception);
	CPPUNIT_TEST_EXCEPTION(testZeroINodes, Exception);
	CPPUNIT_TEST(testDiskSizeChange);
	CPPUNIT_TEST(testBlockSizeChange);
	CPPUNIT_TEST(testInodesArraySizeChange);
	CPPUNIT_TEST(testNewDiskSB);
	CPPUNIT_TEST(testSB);
	CPPUNIT_TEST(testSetterGetters);
	CPPUNIT_TEST(testIllegalInodesArraySize);
	CPPUNIT_TEST(testNotEnoughDiskSpace);
	//CPPUNIT_TEST();
	CPPUNIT_TEST_SUITE_END();

public:
	void setUp(void) {
		cout<<endl;
	}
	void tearDown(void) {
		remove( "FILE_SYS" );		
	}		

protected:	
	void testNullDA(void) {
		SuperBlockData sb(NULL,3);
	}	
	
	void testZeroINodes(void);
	void testNewDiskSB(void);
	void testSB(void);
	void testSetterGetters(void);
	void testDiskSizeChange(void);
	void testBlockSizeChange(void);
	void testInodesArraySizeChange(void);
	void testIllegalInodesArraySize(void);
	void testNotEnoughDiskSpace(void);
};

#endif
